package com.atlassian.extras.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;

import com.atlassian.extras.api.Contact;
import com.atlassian.extras.api.LicenseType;
import com.atlassian.extras.api.Organisation;
import com.atlassian.extras.api.Partner;
import com.atlassian.extras.api.Product;
import com.atlassian.extras.api.ProductLicense;
import com.atlassian.extras.common.DateEditor;
import com.atlassian.extras.common.log.Logger;
import com.atlassian.extras.common.util.LicenseProperties;

public class DefaultProductLicense implements ProductLicense {
	private static final Logger.Log log = Logger
			.getInstance(DefaultProductLicense.class);
	private static final long MILLIS_IN_A_DAY = 86400000L;
	private final int licenseVersion;
	private final String description;
	private final Product product;
	private final String serverId;
	private final Partner partner;
	private final Organisation organisation;
	private final Collection<Contact> contacts;
	private final Date creationDate;
	private final Date purchaseDate;
	private final int maximumNumberOfUsers;
	private final Date expiryDate;
	private final Date maintenanceExpiryDate;
	private final String supportEntitlementNumber;
	private final boolean evaluation;
	private final LicenseType licenseType;
	private final LicenseProperties properties;

	protected DefaultProductLicense(Product product,
			LicenseProperties properties) {
		log.debug("--- Creating license for " + product);

		this.licenseVersion = Integer.valueOf(
				properties.getProperty("licenseVersion", String.valueOf(0)))
				.intValue();
//		this.description = properties.getProperty("Description");
		this.description = "JIRA Enterprise license, 2000 users";
		this.product = product;
		this.evaluation = false;
		this.serverId = properties.getProperty("ServerID");
		this.partner = getPartner(properties);
		this.organisation = new DefaultOrganisation(
				properties.getProperty("Organisation"));
		this.contacts = getContacts(properties);
		this.creationDate = getCreationDate(properties);
		this.purchaseDate = getPurchaseDate(properties);
//		this.expiryDate = getExpiryDate(properties);
		this.expiryDate = null;
//		this.expiryDate = new Date(java.sql.Date.valueOf("2099-12-31").getTime());
//		this.maintenanceExpiryDate = DateEditor.getDate(properties.getProperty(
//				"MaintenanceExpiryDate", "1970-01-01"));
		this.maintenanceExpiryDate = new Date(java.sql.Date.valueOf("2099-12-31").getTime());
		this.supportEntitlementNumber = properties.getProperty("SEN");
//		this.maximumNumberOfUsers = properties.getInt("NumberOfUsers", 0);
		this.maximumNumberOfUsers = 2000;
//		this.licenseType = LicenseTypeAndEditionResolver
//				.getLicenseType(properties.getProperty("LicenseTypeName"));
		this.licenseType = LicenseType.COMMERCIAL;
		this.properties = properties;

		log.debug("--- Done creating license for " + product);
	}

	private Date getCreationDate(LicenseProperties properties) {
		String creationDateString = properties.getProperty("CreationDate",
				"1970-01-01");
		log.debug("Creation date is <" + creationDateString + ">");

		return DateEditor.getDate(creationDateString);
	}

	private Date getPurchaseDate(LicenseProperties properties) {
		String creationDateString = properties.getProperty("CreationDate",
				"1970-01-01");
		String purchaseDateString = properties.getProperty("PurchaseDate",
				creationDateString);
		log.debug("Purchase date is <" + purchaseDateString + ">");

		return DateEditor.getDate(purchaseDateString);
	}

	private Date getExpiryDate(LicenseProperties properties) {
		String expiryDateString = properties.getProperty("LicenseExpiryDate",
				"1970-01-01");
		log.debug("Expiry date is <" + expiryDateString + ">");

		return DateEditor.getDate(expiryDateString);
	}

	public Product getProduct() {
		return this.product;
	}

	public String getServerId() {
		return this.serverId;
	}

	public Partner getPartner() {
		return this.partner;
	}

	public Organisation getOrganisation() {
		return this.organisation;
	}

	public Collection<Contact> getContacts() {
		return this.contacts;
	}

	public Date getCreationDate() {
		return new Date(this.creationDate.getTime());
	}

	public Date getPurchaseDate() {
		return new Date(this.purchaseDate.getTime());
	}

	public Date getExpiryDate() {
		return this.expiryDate != null ? new Date(this.expiryDate.getTime())
				: null;
	}

	public int getNumberOfDaysBeforeExpiry() {
		if (this.expiryDate == null) {
			return 2147483647;
		}

		return getDaysBeforeDate(this.expiryDate);
	}

	public boolean isExpired() {
		return (this.expiryDate != null)
				&& (this.expiryDate.compareTo(new Date()) < 0);
	}

	public Date getMaintenanceExpiryDate() {
		return this.maintenanceExpiryDate != null ? new Date(
				this.maintenanceExpiryDate.getTime()) : null;
	}

	public int getNumberOfDaysBeforeMaintenanceExpiry() {
		if (this.maintenanceExpiryDate == null) {
			return 2147483647;
		}

		return getDaysBeforeDate(this.maintenanceExpiryDate);
	}

	public boolean isMaintenanceExpired() {
		return (this.maintenanceExpiryDate != null)
				&& (this.maintenanceExpiryDate.compareTo(new Date()) < 0);
	}

	public String getSupportEntitlementNumber() {
		return this.supportEntitlementNumber;
	}

	public int getMaximumNumberOfUsers() {
		return this.maximumNumberOfUsers;
	}

	public boolean isUnlimitedNumberOfUsers() {
		return this.maximumNumberOfUsers == -1;
	}

	public boolean isEvaluation() {
		return this.evaluation;
	}

	public String getProperty(String name) {
		return this.properties.getProperty(name);
	}

	private int getDaysBeforeDate(Date date) {
		return (int) ((date.getTime() - System.currentTimeMillis()) / 86400000L);
	}

	private static Partner getPartner(LicenseProperties properties) {
		String partnerName = properties.getProperty("PartnerName");
		return partnerName != null ? new DefaultPartner(partnerName) : null;
	}

	private static Collection<Contact> getContacts(LicenseProperties properties) {
		String contactEmail = properties.getProperty("ContactEMail");
		String contactName = properties.getProperty("ContactName");
		if ((contactEmail != null) || (contactName != null)) {
			ArrayList<Contact> out = new ArrayList<Contact>();
			out.add(new DefaultContact(contactName, contactEmail));
			return out;
			// return Collections.singletonList(new DefaultContact(contactName,
			// contactEmail));
		}

		return Collections.emptyList();
	}

	public int getLicenseVersion() {
		return this.licenseVersion;
	}

	public String getDescription() {
		return this.description;
	}

	public LicenseType getLicenseType() {
		return this.licenseType;
	}

	private static final class DefaultContact implements Contact {
		private final String name;
		private final String email;

		DefaultContact(String name, String email) {
			this.name = name;
			this.email = email;
		}

		public String getName() {
			return this.name;
		}

		public String getEmail() {
			return this.email;
		}
	}

	private static final class DefaultOrganisation implements Organisation {
		private final String name;

		DefaultOrganisation(String name) {
			this.name = name;
		}

		public String getName() {
			return this.name;
		}
	}

	private static final class DefaultPartner implements Partner {
		private final String name;

		DefaultPartner(String name) {
			this.name = name;
		}

		public String getName() {
			return this.name;
		}
	}
}